// /opt/openmpi/bin/mpic++ -lm -o m mpiden.cpp
#include <mpi.h>
//    #undef SEEK_SET
//    #undef SEEK_END
//    #undef SEEK_CUR

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <queue>

using namespace std;
#include "general.h"
#include "mpiden_objects.h"
#include "mpiden_publicvars.h"
#include "mpiden_operations.h"
#include "mpiden_functions.h"

// masa por particula de la sim de 500Mpc es  7.1973e+10 masa solares
// masa por particula de la sim de 60Mpc  es  1.056e+8 masa solares

#define WRITERS 4      // Numero de files que se escribiran en el output
#define INTBOX   500   // 60
#define SNAPNUM  37    // 24
#define FILES    8     // numero de files por snapshot 
#define NPAQMAX 15000  // numero maximo de particulas por paquete de comunicacion

// Structuras a comunicar
MPI_Datatype  Dosint;
MPI_Datatype  Partmpi; 

int  totalsizeR,totalsizeL,maxsizeR,maxsizeL;
int main(int argc, char **argv)
{
  int i,j,ibox;	
  int iy, iz ,sendproc, recvproc;
  float numdens;
  float r0;
  FILE *pfout;
  long int kkk;
  char fileout[200];
  MPI_Datatype  type[2]= {MPI_INT, MPI_INT};
  int blocklen[2]      = { 1, 1};
  MPI_Aint disp[2];
  struct ptcl tmptcl;
  
  MPI_Init (&argc, &argv);
  MPI_Comm_size (MPI_COMM_WORLD, &numprocs);
  MPI_Comm_rank (MPI_COMM_WORLD, &proc);

  // Crea la estructura Dosint
  interDer  = new struct face [2] ;
  disp[0] = (MPI_Aint)&interDer[0].Id - (MPI_Aint)&interDer[0];
  disp[1] = (MPI_Aint)&interDer[0].Grp - (MPI_Aint)&interDer[0];
  MPI_Type_create_struct(2, blocklen, disp, type, &Dosint);
  MPI_Type_commit(&Dosint);
  delete[] interDer;

  read_header();

  numdens=(float)nparticles_total/powf(boxsize,3.); 
  r0 = 0.17*pow(numdens,-1./3.);
  overhead = r0/2.;
    
  nobj   = read_gadget_overlap();
//  nobj=92000;

  
 /* pfout=fopen("/dev/urandom","r");
  fread(&kkk,sizeof(long int),1,pfout);
  fclose(pfout);
  srand48(kkk);*/
   
/*  sprintf(fileout,"MenosParticles.%d.dat",proc);
  pfout=fopen(fileout,"w");
  if(pfout==NULL) {moco("Open failed\n");FIN;}

  for(i=0;i<particle.size();i++)
  {
	  if(drand48()<0.1)
	  {
             fprintf(pfout,"%f %f %f %f %f %f %d\n",
	           particle[i].Pos[0],particle[i].Pos[1],particle[i].Pos[2],
                   particle[i].Vel[0],particle[i].Vel[1],particle[i].Vel[2],
	           particle[i].Id);
	  }
  }
  
  fclose(pfout);
  MPI_Finalize ();
  exit(0);*/

 /* tmptcl.Pos[0]=0.;  tmptcl.Pos[1]=0.;  tmptcl.Pos[2]=0.;
  tmptcl.Vel[0]=0.;  tmptcl.Vel[1]=0.;  tmptcl.Vel[2]=0.;
  tmptcl.Id=-1;
  
  particle.assign(920000,tmptcl);
  sprintf(fileout,"MenosParticles.%d.dat",proc);
  pfout=fopen(fileout,"r");
  if(pfout==NULL) {moco("Open failed\n");FIN;}

  for(i=0;i<particle.size();i++)
  {
      if(fscanf(pfout,"%f %f %f %f %f %f %d",
           &particle[i].Pos[0],&particle[i].Pos[1],&particle[i].Pos[2],
           &particle[i].Vel[0],&particle[i].Vel[1],&particle[i].Vel[2],
           &particle[i].Id)==EOF) break;
  }
 
  particle.erase(particle.begin()+i,particle.end());
  fclose(pfout);*/

  RED; 
  cout << " proceso " << proc ;  
  CYAN;
  cout << " r0 "<< r0 ;
  cout << " np "<< np ;
  cout << " nobj "<< nobj ;
  cout << " nx "<< nx << endl;  DEFA;
  
  lirst      = new int [nx*np*np];
  ll         = new int [particle.size()];

  grid();
//  cout << totalsizeR << "  |||  " << totalsizeL << endl;
  idenBFS(r0);
  MPI_Allreduce(&ngrupos,&maxngrp,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD); 

  interDer  = new struct face [maxovh] ;
  interIzq  = new struct face [maxovh] ;
  externIzq = new struct face [maxovh] ;
  for(i=0;i<maxovh;i++)
  {
	interDer[i] .Id=-1;
	interIzq[i] .Id=-1;
	externIzq[i].Id=-1;
	interDer[i] .Grp=-1;
	interIzq[i] .Grp=-1;
	externIzq[i].Grp=-1;
  }
  interface(interDer,nx-1);// check OK
  interface(interIzq,0);// check OK
 
  MPI_Barrier(MPI_COMM_WORLD); 
  
  cout << "fuera de interface (que sea par el numero de procesos) " << proc << endl;
  sendproc = proc < numprocs - 1 ? proc+1 : 0            ;
  recvproc = proc > 0            ? proc-1 : numprocs - 1 ;
  
  if(proc%2==0)
  {
    MPI_Send(interDer, maxovh,Dosint,sendproc,78,MPI_COMM_WORLD);
    cout << proc << " par envio " << sendproc << endl;
    MPI_Recv(externIzq,maxovh,Dosint,recvproc,53,MPI_COMM_WORLD,&status);
    cout << proc << " par recivio " << recvproc << endl;
  }
  else
  {
    MPI_Recv(externIzq,maxovh,Dosint,recvproc,78,MPI_COMM_WORLD,&status);
  //  cout << proc << " inpar recibio "<< recvproc << endl;
    MPI_Send(interDer, maxovh,Dosint,sendproc,53,MPI_COMM_WORLD);
  //  cout << proc << " inpar envio " << sendproc << endl;
  }

  delete[] interDer;
  MPI_Barrier(MPI_COMM_WORLD);
//  cout << "hola 1!!!  " << proc << endl;
  crearista(); //chequeado 50%
  
  delete[] interIzq;  delete[] externIzq;

//  LCYAN; cout << "llegue al creagrafo  " << proc<<endl ; fflush(stdout); DEFA;
  MPI_Barrier(MPI_COMM_WORLD);

  creagrafo2();
  
//  cout << "tamanhos " << grafo_vertices.size() << " " << grafo_arista.size() << " " << proc << endl << flush ;
  MPI_Barrier(MPI_COMM_WORLD);
  
  numero   = new int [maxngrp*numprocs];
  totalnum = new int [maxngrp*numprocs];
// LCYAN;
// cout << "sale del creagrafo y entra names  " << proc<<endl ; fflush(stdout);
// LCYAN;

  groups_namesBFS2();
 cout << "sale de names  " << proc <<endl ; fflush(stdout);
 FIN;
    
  MPI_Allreduce(&numero,&totalnum,(maxngrp*numprocs),MPI_INT,MPI_SUM,MPI_COMM_WORLD);
  delete [] numero;
  
  write_data(WRITERS);// to check
	
  
  MPI_Finalize ();
  exit(0);
}

int write_data(int nfiles)
{
	int i,h,j,k;
	int recvproc, filegrp;
	int comm_map[numprocs];
	int send_map[numprocs];
	struct ptcl *commbuff;
	vector <struct ptcl> halo;
	char *filename=NULL;

	filegrp =(int) ceilf((float)universalname/(float)nfiles);


        ofstream Salida ;
        sprintf(filename,"Salida.%d.dat",proc);
	if(proc<nfiles) Salida.open(filename);

	for(recvproc=0;recvproc<nfiles;recvproc++)
	{
	     for(i=recvproc*filegrp; i<(recvproc+1)*filegrp -1 && i<universalname;i++)
	     {
		     for(j=0;j<numprocs;j++){ comm_map[j]=0; send_map[j]=0;}
		     comm_map[proc]=numero[i];
                     MPI_Allreduce(&comm_map,&send_map,numprocs,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
		     if(proc==recvproc)
		     {
			     for(h=0;h<numprocs;h++)
			     {
				     if(send_map[h]>0)
				     {
					     commbuff= new struct ptcl [send_map[h]];
                                             MPI_Recv(&commbuff,send_map[h],Partmpi,h,34,MPI_COMM_WORLD,&status);
					     for(k=0;k<send_map[h];k++)
						     halo.push_back(commbuff[h]);
					     delete[] commbuff;
				     }
				     
			     }
			     if(halo.size()!=totalnum[i]){moco("la cagaste al escribir\n"); FIN;}

                             // Escribiendo la salida
			     Salida << halo ;
		     }
		     else
		     {
			     if(comm_map[proc]>0)
			     {
				     commbuff= new struct ptcl [comm_map[proc]];
				     for(h=0;h < grupo[i].members.size();h++)
					     commbuff[h]=*(grupo[i].members[h]);
			     	     MPI_Send(&commbuff,comm_map[proc],Partmpi,recvproc,34,MPI_COMM_WORLD);
				     delete[] commbuff;
			     }
		     }

	     }
	}
  
	if(proc<nfiles) Salida.close();
	return 0;
}

int groups_namesBFS(void)
{
/*
Recorre el grafo... y renombra universalmente en cada Nodo
*/
	int i,j,k,ktot,sendproc,h,summ;
	int *rename, *subtot;
        int total;
	long int kk;
	struct point u,v,der,izq ; 
	vector <point>::iterator ptr ;
	cola Q;
//	int root_proc;

	rename = new int [maxngrp*numprocs];
	subtot = new int [numprocs];
	for(i=0;i<maxngrp*numprocs;i++)
		rename[i] = -1; 

	         cout << " <-proc ; conectando grupos: "<< grafo_vertices.size() << endl;
	         for(i=0;i<grafo_vertices.size();i++)
	         {   
//	             cout << " G-Vertice "<< i <<endl; fflush(stdout);

                     if(grafo_vertices[i].visitado) continue ;
                     grafo_vertices[i].visitado  = true ;
                     grafo_vertices[i].distancia = 0    ;
                     //Encolar(Q, s);
	             Q.push(grafo_vertices[i]);
		
                     do
                     {
                        // extraemos el nodo u de la cola Q y exploramos 
	                // todos sus nodos adyacentes
                        u     = Q.front();
   	                Q.pop();
///	                 cout << "@ "<< Q.size() <<endl; fflush(stdout);
	       
                        for(j=0;j<grafo_arista.size();j++)
	                {
		             if( u.name == (*(grafo_arista[j].r)).name)
		             {
//	               cout << "U "<< u.name <<endl; fflush(stdout);
			           if(!(*(grafo_arista[j].l)).visitado)
			           {
                                        (*(grafo_arista[j].l)).visitado    = true            ;
                                        (*(grafo_arista[j].l)).distancia   = u.distancia + 1 ;
		                        (*(grafo_arista[j].l)).padre = grafo_vertices.begin()+(*(grafo_arista[j].r)).name;
		                        //(*(grafo_arista[j].l)).padre = 
					//	find_if( grafo_vertices.begin(), grafo_vertices.end(), 
					//			look_vertice_name(*(grafo_arista[j].r)) );
	                                Q.push(*(grafo_arista[j].l))     ;  //Encolar v en Q
			           }
		             }
		             if( u.name==(*(grafo_arista[j].l)).name)
		             {
			           if(!(*(grafo_arista[j].r)).visitado)
			           {
                                        (*(grafo_arista[j].r)).visitado    = true            ;
                                        (*(grafo_arista[j].r)).distancia   = u.distancia + 1 ;
		                        (*(grafo_arista[j].r)).padre       = grafo_vertices.begin()+(*(grafo_arista[j].l)).name;
		                        //(*(grafo_arista[j].r)).padre = 
				        //	find_if( grafo_vertices.begin(), grafo_vertices.end(), 
				        //			look_vertice_name(*(grafo_arista[j].l)) );
	                                Q.push(*(grafo_arista[j].r));//Encolar(Q, v);
			           }
		             }
	                }
                     }while(!Q.empty());
	             //agotadas todas las adyacencias salimos
	         }

		
		 //renombrando padres 
	         universalname=0;
	         for(i=0;i<grafo_vertices.size();i++)
	         {
		      u=grafo_vertices[i];
	              ptr=u.padre;
	              // es padre ?
		      if( ptr ==(vector <point>::iterator )NULL)
			      universalname++;
	         }
		 
		 for(i=0;i<numprocs;i++)
			 subtot[i]=0;
		 subtot[proc] = universalname;
		cout << subtot[proc] << endl << flush;
		 MPI_Allreduce(&subtot[proc],&total,numprocs,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
		cout << total << endl; 

		 summ=0;
		 for(i=0;i<=proc;i++)
		 {
			 subtot[i]=subtot[i]+summ;
			 summ = summ+ subtot[i];
		 }
		 
	         universalname=subtot[proc];
	         for(i=0;i<grafo_vertices.size();i++)
	         {
		      u=grafo_vertices[i];
	              ptr=u.padre;
	
	              // es padre ?
		      if( ptr ==(vector <point>::iterator )NULL)
		      {
			      rename[grafo_vertices[i].name] =universalname; 
			      universalname++;
		      }
	         }
		
		 
	         for(i=0;i<grafo_vertices.size();i++)
   	         {
	      	      u=grafo_vertices[i];
	              ptr=u.padre;

		      // es hijo de
		      if( ptr !=(vector <point>::iterator )NULL)
	      	      {
		      	      do
		 	      {
			           v=*ptr; ptr=v.padre;
                                   if(ptr==(vector <point>::iterator)NULL)
				           break;
  		              }while(1);
	   	              if(grafo_vertices[i].name<maxngrp*numprocs)
			      {
				      rename[grafo_vertices[i].name] = rename[v.name] ;
			      }
			      else
			      {
				      LGREEN;
				      cout<< "la cagaste aca  " << proc << " " <<grafo_vertices[i].name <<endl;
				      DEFA;
			      }
	   	      }
 	         }
		 
	for(i=0;i<maxngrp*numprocs;i++)
	{
            k = rename[i]>-1 ? 1 : 0; ktot=0;
            MPI_Allreduce(&k,&ktot,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
	    if(ktot>1)
	    {
		    cout << rename[i] << " | " << proc << " -- " << ktot << endl;
		    moco("mas de uno en rename\n");FIN;
	    }
	    if(ktot==0)
	    {
		    //el grupo no existe pero eso esta permitido
		    if(i==maxngrp*numprocs-1)break;
		    continue;
	    }
	    k = k==1 ? proc : -1;
	    MPI_Allreduce(&k,&ktot,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD);
	    MPI_Barrier(MPI_COMM_WORLD);
            MPI_Bcast(&rename[i],1,MPI_INT,ktot,MPI_COMM_WORLD);
	    MPI_Barrier(MPI_COMM_WORLD);
	}

 
	ofstream Salida ;
      	char fileout[100];
      	sprintf(fileout,"Nombres.%d.dat",proc);

      	Salida.open(fileout);
	for(i=0;i<maxngrp*numprocs;i++)
	{
		if(rename[i]>-1)
			Salida << i << " renombrado a: " << rename[i] << endl;
	}
      	Salida.close();

	for(i=0;i<particle.size();i++)
	{
		particle[i].Idgrupo=rename[particle[i].Idgrupo];
                if(particle[i].Idgrupo>=0)numero[particle[i].Idgrupo]++;
	}
	return 0;
};

int creagrafo2(void)
{
  int i,j,k,grp;
  struct link  tmplink;
  struct point tmp_point,look;
  vector<int> registro;
  vector<int>::iterator isth;
  queue<int> Buscados,Encontrado;
  queue<struct equival> Delqueue;
  int nombre,root_proc,signal,offset;
  int *parent,*halla;
  int current,sendproc,nfindings;
  int current_size,name_to_search;
  int name_finding;
  struct equival t ;
  vector <equival>::iterator older;
  vector <struct point> old_vertices ;        // sobre la descomposicion de dominio
  size_t buffersize;
  int *posbuf;
  int numero_cosmetico;
	  
  vector <point>::iterator loc_ver;
  //ofstream Salida1,Salida2 ;
  char fileout[100];
  
  /*sprintf(fileout,"Recivo.%d.dat",proc);
  cout << proc<<" "<<fileout << endl;
  Salida1.open(fileout);
  sprintf(fileout,"Mando.%d.dat",proc);
  Salida2.open(fileout);*/

  
  /*buffersize=(((10000+MPI_BSEND_OVERHEAD)*sizeof(int)));
  posbuf=(int *)malloc(numprocs*buffersize);

  MPI_Buffer_attach(posbuf,(numprocs-1)*buffersize);*/
  signal=0;
  //cout << proc<<" hasta aca estamos\n" <<flush;
  
		  
  for(root_proc=0;root_proc < numprocs ; root_proc ++)
  {
 //root_proc = 0 ;
// 	  RED; cout << /*proc <<*/ " ahora es root " << root_proc << endl; DEFA;
	  current_size= arista.size();
	  MPI_Bcast(&current_size,1,MPI_INT,root_proc,MPI_COMM_WORLD);
	  //if(current_size==0)continue;
	  if(current_size==0)moco("\n\n OORTT \n\n");
//cout << "ilala "<< endl;
	  if(proc==root_proc)
	  {
		//preguntar y recivir los vertices forman arista con los vertices preguntados
		  for(i=0;i< arista.size();i++)//carga en la cola y el registro los vertices a preguntar
		  {
			cout << setw(40) << "\r Porcentaje arista " << 100.0*i/arista.size() ;
			  isth=find(registro.begin(),registro.end(),arista[i].local);
			  if(isth==registro.end() && arista[i].local>=0)
			  { 
				  
				  registro.push_back(arista[i].local);
				  Buscados.push(arista[i].local); 
			  }
			  isth=find(registro.begin(),registro.end(),arista[i].externa);
			  if(isth==registro.end() && arista[i].externa>=0)
			  { 
				  
				  registro.push_back(arista[i].externa);
				  Buscados.push(arista[i].externa); 
			  }
		  }
	cout << endl <<"Done!, Buscados.size(): " << Buscados.size() <<endl << "Soy el proceso : " << proc << " como root" << endl <<flush;
		numero_cosmetico=Buscados.size();  
		  do//synchronous
		  {	   
			  
		   	  nombre = Buscados.front(); 
//try{
Buscados.pop();//} catch (std::exception& X) {cerr<< " kk1 " <<X.what()<< endl;FIN;}
//	  cout << proc << " #";
//			cout << setw(50) << "\r Falta Porcentaje Buscados: " << 100.0*Buscados.size()/numero_cosmetico << flush;
			  if(nombre<0) {cout << "\n GUATA FAAACKKK\n";}
		     	  //ask each process for nombre 
		       	  for(sendproc=0;sendproc < numprocs ; sendproc ++)
			  {
			       	  if(sendproc==root_proc) continue;
//			          cout << proc << " estoy enviando al  "<< sendproc << endl << flush; 
      				  MPI_Send(&nombre,1,MPI_INT,sendproc,66,MPI_COMM_WORLD);
				  
      				  MPI_Recv(&nfindings,1,MPI_INT,sendproc,67,MPI_COMM_WORLD,&status);
      				  if(nfindings<=0) continue;

				  try{parent= new int [nfindings];}catch (std::exception& X) 
				  {cerr<< " klkklkll " << X.what()<< endl;FIN;}
				  MPI_Recv(parent,nfindings,MPI_INT,sendproc,68,MPI_COMM_WORLD,&status);
				  
      				  for(k=0;k<nfindings;k++)
      				  {
//			                  cout << k << " /// " << nfindings << endl;
      					  isth=find(registro.begin(),registro.end(),parent[k]);
      					  if(isth==registro.end() && parent[k]>=0)
      					  {
      						  registro.push_back(parent[k]);
      						  Buscados.push(parent[k]); 
      					  }
      					  t.local   = nombre   ;
      					  t.externa = parent[k]   ; 
      					  arista.push_back(t)  ;//extiende el dominio
      				  }
//				  for(j=0;j<nfindings ;j++) {CYAN; cout << "la cgaf "<< parent[j] << endl <<flush; DEFA;}
//				  try{
				delete [] parent;
//}catch (std::exception& X) {cerr<< " ssss3 " << X.what()<< endl;FIN;}
				  //Salida1 << endl;
  			  }
			  signal=1;
		   	  if(Buscados.empty()) signal= ( -5);

//			  cout << " \r Nuevo " << proc << " y senial "<< signal/*<<endl*/<< flush; 
//			  MPI_Barrier(MPI_COMM_WORLD);
//			  cout << " despues root "<< proc <<endl<< flush; 
			  MPI_Bcast(&signal,1,MPI_INT,root_proc,MPI_COMM_WORLD);
		  }while(signal>0);//synchronous

	  }
	  else
	  {
		  //contesta y manda los vertices forman arista con los vertices preguntados
		  do //synchronous
		  {
//			  cout << /*proc << */" estoy esperando a  "<< root_proc << endl << flush; 
		     	  MPI_Recv(&name_to_search,1,MPI_INT,root_proc,66,MPI_COMM_WORLD,&status);
//			  cout << proc << " busco el:  "<< name_to_search << endl << flush; 
			  if(name_to_search<0) {cout << "\n\n Que prong B!!?" << name_to_search ; FIN;}
		          if(!Encontrado.empty()) cout << "\n\n Que prong C!!? \n\n" ;
   			  nfindings=0;
			  //cout << "encuentro proc "<< proc << endl;
      			  for(j=0;j<arista.size();j++)
   			  {
       				  if( name_to_search == arista[j].local)
       				  { 
	 				  name_finding=arista[j].externa ; nfindings++;
					  Encontrado.push(name_finding);
				   	  Delqueue.push(arista[j]); 
					  continue;
				  }
       				  if( name_to_search == arista[j].externa )
       				  { 
	 				  name_finding=arista[j].local ;  nfindings++; 
					  Encontrado.push(name_finding);
			  		  Delqueue.push(arista[j]);
					  continue;
       				  }
   			  }
			  
			  if(nfindings!=Encontrado.size()) cout << "\n\n Que prong A!!? \n\n" ;
			  //cout << proc<<": tantos: " << Encontrado.size() << endl;
   				  
			  while(!Delqueue.empty())
			  {
				  t = Delqueue.front(); //try {
				Delqueue.pop();
//}				  catch (std::exception& X) {cerr<< " kk2 " << X.what()<< endl;FIN;}
				  older = find_if( arista.begin(), arista.end(), comp_arista(t) );
				  if(older == arista.end())
				  {
					  //cout << t.local << " ----  " << t.externa << endl <<flush;
					  moco("HEY!!!!!!!!!!!\n");FIN;
				  }
//				  try{
arista.erase(older,older+1);
// // se deshace de las aristas enviadas
//}				  catch (std::exception& X) {cerr<< " kk3 " << X.what()<< endl;FIN;}
			  }
			  
   			  if(Encontrado.empty())
   			  {
       				  nfindings=-1;
       				  MPI_Send(&nfindings,1,MPI_INT,root_proc,67,MPI_COMM_WORLD);
   			  }
   			  else
   			  {
       				  MPI_Send(&nfindings,1,MPI_INT,root_proc,67,MPI_COMM_WORLD);
				  j=0;
//				  try{ 
halla= new int [nfindings];
//}				  catch (std::exception& X) {cerr<< " kk6 " << X.what()<< endl;FIN;}
       				  while(!Encontrado.empty())
       				  {
					  if(j>=nfindings) cout << "\n\n BUGGGGGGG \n\n";

					  if(Encontrado.front() < 0) {cout<< "ENVIO::: " << Encontrado.front() <<endl <<flush;}
					  
//	 				  try{
halla[j] = Encontrado.front(); 
//}					  catch (std::exception& X) {cerr << " ll3 " << X.what()<< endl;FIN;}
//					  try{ 
Encontrado.pop();
//}catch (std::exception& X) {cerr << " kk3 " << X.what()<< endl;FIN;}
					  j++;
				  }


//				  for(j=0;j<nfindings ;j++) {CYAN; cout << "la cgafadsa "<< halla[j] << endl <<flush; DEFA;}
				  MPI_Send(&halla[0],nfindings,MPI_INT,root_proc,68,MPI_COMM_WORLD);
//				  try{
delete [] halla;
//}catch (std::exception& X) {cerr<< " kk3 " << X.what()<< endl;FIN;}
   			  }
			          
//			  cout << proc <<": quedaron: " << Encontrado.size() << endl <<flush;
//			  MPI_Barrier(MPI_COMM_WORLD);
//			  cout << "bcast client  "<< proc <<endl<< flush; 
      			  MPI_Bcast(&signal,1,MPI_INT,root_proc,MPI_COMM_WORLD);
//			  cout << "after bcast  "<< proc <<endl<< flush; 
		  }while(signal>0);//synchronous
//		  cout << "kaquita  "<< proc <<endl<< flush; 
	  }
//	  cout << "\n\n PERO!!!  " << proc << "\n\n"<<flush;
	MPI_Barrier(MPI_COMM_WORLD);

  } // cambia de root_proc
 
  //free(posbuf);
  //
//			  MPI_Barrier(MPI_COMM_WORLD);
  cout << "FUERA DEL SYNCHRONOUS  " << proc << "\n"<<flush;
  
  for(i=0;i< registro.size();i++)
  {
	  tmp_point.visitado = false          ;
	  tmp_point.distancia = 0             ;
	  tmp_point.padre = (vector <point>::iterator )NULL              ;
	  tmp_point.name = registro[i]        ;
	  grafo_vertices.push_back(tmp_point) ;
  }

  for(i=0;i< arista.size();i++)
  {
	  if(arista[i].local!=-1 && arista[i].externa!=-1)
	  {
			     
		  look.name=arista[i].local;
       		  //tmplink.r = find_if( grafo_vertices.begin(), grafo_vertices.end(), as_name(look) );
		  tmplink.r = grafo_vertices.begin() + arista[i].local   ;
		  look.name=arista[i].externa;
       		  //tmplink.l = find_if( grafo_vertices.begin(), grafo_vertices.end(), as_name(look) );
		  tmplink.l = grafo_vertices.begin() + arista[i].externa ; 
		  grafo_arista.push_back(tmplink)                ;
	  }
  }       

//  try{
registro.clear();
//}catch (std::exception& X) {cerr<< " kk3 " << X.what()<< endl;FIN;}
	
  //MPI_Buffer_detach(posbuf,&k);
 return 0; 
};

int crearista(void)
{
  int i,j;
  vector <struct equival> palito;
  vector <equival>::iterator older;
  struct equival ver,t;
  int idcheck, sisa;
  char fileout[100];

//  ofstream Salida ;
//  sprintf(fileout,"arista.proc_%d.dat",proc);
//  Salida.open(fileout);
  
  for(i=0;i<maxovh;i++)
  {
     ver.local=interIzq[i].Grp;
     if(ver.local==-1) continue ;
     idcheck=interIzq[i].Id;
  //   Salida << interIzq[i].Id << " | " << externIzq[i].Id << endl;
  //   Salida << interIzq[i].Grp << " + " << externIzq[i].Grp << endl;

     ver.externa=-2;
     for(j=0;j<maxovh;j++)
	if(externIzq[j].Id == idcheck)
		ver.externa=externIzq[j].Grp;
     
     //if(ver.externa==-2) { moco("la cagaste en crearista\n") ; FIN;} // Nadie es perfecto :-P
     if(ver.externa==-2) continue ;
     if(ver.externa==-1) continue ;
    
     older = find_if( palito.begin(), palito.end(), 
		     comp_arista(ver) );
     if (older != palito.end()) continue ;
     
     palito.push_back(ver);

  }
//  Salida.close();
  
  sisa = palito.size();
  MPI_Allreduce(&sisa,&maxequival,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD);

 
  for(i=0;i<palito.size();i++)
  {
         // Salida << palito[i].local << "  |  " << palito[i].externa << endl;
          arista.push_back(palito[i]);
  }

  
  palito.clear();

  return 0;
};

int interface(struct face *franja, int ix)
{
  int i, h,ibox;
  int iy, iz;
  char fileout[100];

/*S  ofstream Salida ;
  sprintf(fileout,"interface.%d.proc_%d.dat",ix,proc);
  Salida.open(fileout);*/
 cout << proc << " interface <<"<< endl ;
  h=0;
  for( iy = 0 ; iy < np ; iy++)
  { 
      for( iz = 0 ; iz < np ; iz++)
      {
        ibox=(ix * np + iy) * np + iz ;
        i=lirst[ibox];
        if(i==-1)continue;
        do
        {
          i=ll[i] ;
	  
	  if((particle[i].Pos[0]         < 2.*overhead && ix == 0   ) ||
	     (xsize - particle[i].Pos[0] < 2.*overhead && ix == nx-1)    )
	  {
	//     Salida << particle[i].Id << " ";
	/*     Salida << particle[i].Pos[0] << " ";
	     Salida << particle[i].Pos[1] << " ";
	     Salida << particle[i].Pos[2] << endl;*/
	     franja[h].Id  = particle[i].Id ;
	     franja[h].Grp = particle[i].Idgrupo>=0 ? maxngrp*proc + particle[i].Idgrupo : -1 ;
///S	     Salida << franja[h].Grp << " +++ " << franja[h].Id  << endl;
	     h++ ;
	  }
	  if(h>maxovh) moco("la cagaste en la interface\n"); //ojoooo aca
        } while( i != lirst[ibox] ); /*fin laso particulas del grid*/
      } /*fin iz*/
  } /*fin iy*/
///S  Salida.close();
 cout << proc << " interface >> "<< ix<< endl ;
  return 0;
}

int change_coord(void)
{
  float cb ,lb,d; 
  int i;
  float c1,c2;
  c1=0;c2=10000000;
  cb = (boxsize/(float)numprocs)*(float)proc - overhead ;
//  lb = boxsize/(float)numprocs ;
//  d  = lb + 2.*overhead;

  for(i=0;i<particle.size();i++)
  {
    particle[i].Pos[0] = particle[i].Pos[0] - cb ;
    if(particle[i].Pos[0] < 0.) 
	particle[i].Pos[0] = particle[i].Pos[0] + boxsize ;
    if(particle[i].Pos[0] > boxsize /*+2.*overhead*/) 
        particle[i].Pos[0] = particle[i].Pos[0] - boxsize ;// - 2.*overhead; 
    if(particle[i].Pos[0]<c2)c2=particle[i].Pos[0];
    if(particle[i].Pos[0]>c1)c1=particle[i].Pos[0];

  }
  cout << " change out: " << c1 << " y " << c2 << endl;
  return 0;
}

int read_header(void)
{
  int  npproc;
  int i,j,k;
  int numpartfile,numpartfilemax,numpart;
  char filename[200];
  FILE *fd;
  float boxsizet;
  
  printf("\033[22;33m proc: %d FILES: %d numprocs%d \033[22;0m \n",proc,FILES,numprocs);
  fflush(stdout);
  if( numprocs < FILES )
  {
    BLUE; printf("proceso: %d\n",proc);
    moco("el numero de procesos es menor que el nunero de files\n");
    printf("numero de procesos: \033[22;32m %d \033[22;0m numero de files: \033[22;32m %d \033[22;0m \n",
            numprocs,proc);  FIN;
  }

  numpartfile=0;  numpartfilemax=0;  numpart=0;
  if( proc < FILES )
  {
    //sprintf(filename,"%dmpcdata/snapshot_0%d.%d",INTBOX,SNAPNUM,proc); 
    sprintf(filename,"/iate/disco2/users/dpaz/MPIden2/%dmpcdata/snapshot_0%d.%d",INTBOX,SNAPNUM,proc); 
//    cout<< filename << endl;
    fd=fopen(filename,"r"); if(fd==NULL) {cout << filename <<" @@@@ "<<proc << endl;moco("fallo el open\n"); FIN;}

    skip(fd); my_fread(&header1, sizeof(header1), 1, fd); skip(fd); skip(fd);
  //  for(i=0;i<6;i++)printf("masa particula %f\n",header1.mass[i]);
  //  for(i=0;i<6;i++)printf("numero particula %d\n",header1.npart[i]);

    for(i=0;i<6;i++)
	    numpartfile+=header1.npart[i];
    if(proc==0)
	    for(i=0;i<6;i++){numpart+=header1.npartTotal[i];}
    
    boxsizet=header1.BoxSize;
    if(proc==0)boxsize=header1.BoxSize;
  }

  MPI_Bcast(&boxsize,1,MPI_FLOAT,0,MPI_COMM_WORLD);

  if( proc < FILES && boxsizet!=boxsize)
  {
	  moco("Diferentes Boxsizes\n"); FIN;
  }

  MPI_Bcast(&numpart,1,MPI_INT,0,MPI_COMM_WORLD);
  nparticles_total=numpart;
//  printf("\033[01;36m NUMERO TOTAL %d \033[01;0m\n",nparticles_total);fflush(stdout);

  numpartfilemax *= 1 + (int)ceilf(2.*overhead/boxsize);
  if(proc < FILES )fclose(fd);
  return 0;
  
}

int read_gadget_overlap(void)
{
  int npproc;
  int i,j,k,ss,a,b;
  int numpartfile,numpartfilemax,coco;
  char filename[200];
  FILE *fPos, *fVel, *fId;
  float xx[3],vv[3];
  int npaqs, ind;
  int nsend,nnn;
  float lolo;
  struct ptcl *posbuf;
  size_t buffersize;
  int contpos, npprocold;
  int ix,iy,iz;
  int iov,nov,id;
  float xdesp, boxsizet,ladosize;
  int *npaq;
  struct ptcl *paq;
  struct ptcl tmptcl,nulaptcl;

  //  MPI_Datatype  Partmpi; es publico ahora
  MPI_Datatype  type[5]= {MPI_FLOAT, MPI_FLOAT, MPI_INT, MPI_INT, MPI::BOOL};
  int blocklen[5]      = { 3, 3, 1, 1, 1};
  MPI_Aint disp[5];
  
  numpartfile=0;  numpartfilemax=0;  
  //Abre el archivo lee el header e inicializa los punteros al file
  if( proc < FILES )
  {
    //sprintf(filename,"%dmpcdata/snapshot_0%d.%d",INTBOX,SNAPNUM,proc); //printf(filename);
    sprintf(filename,"/iate/disco2/users/dpaz/MPIden2/%dmpcdata/snapshot_0%d.%d",INTBOX,SNAPNUM,proc); 

    fPos=fopen(filename,"r"); if(fPos==NULL){ moco("fallo el open\n"); FIN;}
    fVel=fopen(filename,"r"); if(fVel==NULL){ moco("fallo el open\n"); FIN;}
    fId =fopen(filename,"r"); if(fId ==NULL){ moco("fallo el open\n"); FIN;}

    fseek(fPos,sizeof(int),SEEK_CUR);
    my_fread(&header1, sizeof(header1), 1, fPos); 
//    for(i=0;i<6;i++)printf("masa particula %f\n",header1.mass[i]);
//    for(i=0;i<6;i++)printf("numero particula %d\n",header1.npart[i]);
    
    fseek(fPos,2*sizeof(int),SEEK_CUR);
    fseek(fVel,sizeof(header1)+3*sizeof(int),SEEK_CUR); 
    fseek(fId, sizeof(header1)+3*sizeof(int),SEEK_CUR); 

    for(i=0;i<6;i++)
 	    numpartfile+=header1.npart[i];

    fseek(fVel,sizeof(float)*3*numpartfile + 2*sizeof(int),SEEK_CUR); // para las vel saltamos un bloque
    fseek(fId, sizeof(float)*6*numpartfile + 4*sizeof(int),SEEK_CUR); // para los Ids 2 bloques
  }

  MPI_Allreduce(&numpartfile,&numpartfilemax,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD); 

  ladosize = (float)boxsize/(float)numprocs;
  nov      = (int)floorf((float)ladosize/(float)overhead);
  overhead = ladosize/(float)nov; // redefine un overhead divisible

////////////////////DEFINICION DE LOS GRIDS///////////////////////
  xsize = (boxsize/(float)numprocs + 2.*overhead);

  np=(int)floorf(boxsize/overhead)       ; if(np>512)np=512 ;
  nx=(int)floorf(xsize  /(2.0*overhead)) ; if(nx>512)nx=512 ;
  
  facbinx= (double)nx/(double)xsize   ;
  facbinp= (double)np/(double)boxsize ;
//////////////////////////////////////////////////////////////////
  //return 0;

  printf("overhead usado: %f boxisze %f xsize %f\n",overhead,boxsize,xsize);

  numpartfilemax = numpartfilemax + (int)((float)numpartfilemax*(2.*overhead/boxsize));

  npaqs    = numpartfilemax/NPAQMAX +1; // numero de paquetes
  
  for(i=0;i<3;i++) nulaptcl.Pos[i] = 0. ;
  for(i=0;i<3;i++) nulaptcl.Vel[i] = 0. ;
                   nulaptcl.Id     = -1 ;
                   nulaptcl.Idgrupo   = -1 ;
                   nulaptcl.visitado  = false ;

 
  paq  =new struct ptcl [numprocs*NPAQMAX];
  npaq =new int [numprocs];


  // creamos la estructura para comunicar los paquetes en MPI
  disp[0] = (MPI_Aint)&paq[0].Pos       - (MPI_Aint)&paq[0];
  disp[1] = (MPI_Aint)&paq[0].Vel       - (MPI_Aint)&paq[0];
  disp[2] = (MPI_Aint)&paq[0].Id        - (MPI_Aint)&paq[0];
  disp[3] = (MPI_Aint)&paq[0].Idgrupo   - (MPI_Aint)&paq[0];
  disp[4] = (MPI_Aint)&paq[0].visitado  - (MPI_Aint)&paq[0];

  MPI_Type_create_struct(5, blocklen, disp, type, &Partmpi);
  MPI_Type_commit(&Partmpi);

  buffersize=(((NPAQMAX+MPI_BSEND_OVERHEAD)*sizeof(struct ptcl)));
  if(proc==0)
  {
    RED; printf("Buffer size is %f Mbytes\n",(float)buffersize/1024./1024.); 
    DEFA; fflush(stdout);
  }
  
  posbuf=(struct ptcl*)malloc(numprocs*buffersize);

  contpos=0;
  MPI_Buffer_attach(posbuf,(numprocs-1)*buffersize);
  for(i=0;i<npaqs;i++)
  {
    for(j=0;j<numprocs*NPAQMAX;j++) 
	  paq[j]=nulaptcl; 
    if(proc==0)
    {
      printf(" %d Tranzando %d # %d bloque: \033[01;36m %d / %d \033[01;0m\r",proc,a,b,i,npaqs);
      fflush(stdout);
    }

    for(j=0;j<numprocs;j++) npaq[j]=0;
    npproc=0;a=0;b=500000000;
    if( proc < FILES )
    {

      // lectura de los paquetes 
      for(j=0;j<NPAQMAX && contpos<numpartfile ;j++,contpos++)
      {
           my_fread(&xx,sizeof(float),3,fPos);
           my_fread(&vv,sizeof(float),3,fVel);
           my_fread(&id,sizeof(int  ),1,fId ); tmptcl.Id =id ;
	   if(drand48()>0.5)continue;//if(contpos==0)cout << "CUIDADO BOOST";//BOOST
           //controla periodicidad
	   tmptcl.Idgrupo=-1; // inicializandolo para la identificacion
	   tmptcl.visitado=false; // inicializandolo para la identificacion
           for( k = 0 ; k < 3 ; k++ )
           {
             if( xx[k] >= boxsize ) xx[k] -= boxsize;
             if( xx[k] < 0. )        xx[k] += boxsize;
             if( xx[k] < 0. ||  xx[k] >= boxsize  )  moco("-------b-size 3\n");
           }

       	   for(k=0;k<3;k++){ tmptcl.Pos[k]=xx[k] ;
                             tmptcl.Vel[k]=vv[k] ;}

           nsend=(int)floorf(numprocs*xx[0]/boxsize); //nodo al que va la ptcl
	//change coords
           tmptcl.Pos[0]=xx[0]-boxsize/numprocs*nsend+2.0*overhead;
	   tmptcl.Pos[0]+=tmptcl.Pos[0]<0        ? boxsize:0;
	   tmptcl.Pos[0]-=tmptcl.Pos[0]>=boxsize  ? boxsize:0;
           //change coords

           if(nsend>= numprocs || nsend < 0){moco("LA CAGASTE");printf("nsend: %d\n",nsend);FIN;}
           if(nsend==proc) npproc++; 
        
	   // descompone en rodajas disjuntas
	   paq[nsend*NPAQMAX + npaq[nsend]]=tmptcl; npaq[nsend]++;

	   if(tmptcl.Pos[0]>=ladosize)// transmitimos 2 overheads
           {
               nsend= nsend == numprocs-1 ? 0: nsend+1;
               if(nsend==proc) npproc++; 
		tmptcl.Pos[0]=xx[0]-boxsize/numprocs*nsend+2.0*(double)overhead; 
 		   //tmptcl.Pos[0]+=tmptcl.Pos[0]<0        ? boxsize:0;
 		   if(tmptcl.Pos[0]<0)tmptcl.Pos[0]=tmptcl.Pos[0]+boxsize;
		   //tmptcl.Pos[0]-=tmptcl.Pos[0]>=boxsize  ? boxsize:0;
		   if(tmptcl.Pos[0]>=boxsize)tmptcl.Pos[0]=tmptcl.Pos[0]-boxsize;
		   
	       paq[nsend*NPAQMAX + npaq[nsend]]=tmptcl; npaq[nsend]++;
           }
      } 

      //carga las particulas propias
      for(k=0;k<npproc;k++)
      {
         tmptcl = paq[proc*NPAQMAX + k];
	 particle.push_back(tmptcl) ;
      }

      for(j=0;j<numprocs;j++) 
      {
         if(j!=proc)
         {
           ind=j*NPAQMAX; 
	   MPI_Bsend(&paq[ind],NPAQMAX,Partmpi,j,33,MPI_COMM_WORLD);
	   for(k=0;k<npaq[j];k++) if(paq[ind+k].Id<0) {moco("SOS CULCPABLE");FIN;}
         }
      }
    } //fin del if de los lectores

    // lazo para recivir
    for(j=0;j<FILES;j++)
    {
        if(j!=proc)
        {
            ind=j*NPAQMAX; 
            MPI_Recv(&paq[ind],NPAQMAX,Partmpi,j,33,MPI_COMM_WORLD,&status);
            try
            {
               for(k=0;k<NPAQMAX;k++)
               {
    	          if(paq[k+ind].Id>=0)
		  {
			  lolo=(float)particle.size()*(float)sizeof(struct ptcl)/1024.0/1024.0;
			  particle.push_back(paq[k+ind]) ;
		  }
               }
            }
            catch(bad_alloc) 
            {
                cout << endl << particle.size()<< " ja " 
                << sizeof(struct ptcl) <<endl << proc 
                << "  _>>>>>>>>>>>> " <<lolo << endl;moco("llegossss");FIN;
            }
       }
    }

    if( proc < FILES )
    {
        k=0; 
	MPI_Buffer_detach(posbuf,&k);MPI_Buffer_attach(posbuf, k);
    }
   
  }

  //fin del lazo de los paquetes
  if( proc < FILES )
  {
    fclose(fPos);
    fclose(fVel);
    fclose(fId);
  }
////////////////////////////////////////////////////////////////////////////////////////
//        ofstream Salida ;
//        sprintf(filename,"recL.%d.dat",proc);
//	Salida.open(filename);
 //       ofstream Salidaa ;
  //      sprintf(filename,"recR.%d.dat",proc);
//	Salidaa.open(filename);
 // for(i=0;i<particle.size();i++){
//	if(particle[i].Pos[0]<2.0*overhead) Salida << particle[i].Pos[0] << " " << particle[i].Id << endl;}
 // Salida.close();
//  for(i=0;i<particle.size();i++){
//	if(particle[i].Pos[0]>=ladosize) Salidaa << particle[i].Pos[0] << " " << particle[i].Id << endl;}
//  Salidaa.close(); 
////////////////////////////////////////////////////////////////////////////////////////

  fflush(stdout);
  if(npproc>numpartfilemax)
  {
    moco("NPROC > NUMPARTFILEMAX: ");
    printf("proc=%d npproc=%d numpartfilemax=%d\n",proc,npproc,numpartfilemax);
    fflush(stdout);
    FIN;
  }
    
  MPI_Buffer_detach(posbuf,&k);
  
  

  free(posbuf);
  delete[] npaq; delete[] paq;
  return(particle.size());
/*Termino de leer y distribuir*/
}

int idenBFS(float r0)
{
	int i,j,u,v;
	float percent,pp;
	queue  <int> Q;
        vector <int> listvec;
	struct grp halotmp;
//cout << proc << " entro iden"<<endl;
//	cout << "I'm in!  " << proc << endl;
	fflush(stdout);
	ngrupos=0;
	pp=(float) particle.size();
	for(i=0;i<particle.size();i++)
	{   
            percent= ((float) i/pp)*100.;
	    if(fmodf(percent,10.)==0)
	    cout << "procesando "<< percent  << " % : proc: " << proc << flush << endl;
            if(particle[i].visitado) continue ;
            particle[i].visitado  = true ;
            //Encolar(Q, s);
	    
	    halotmp.name = ngrupos;
	    halotmp.members.push_back(&particle[i]);
	    Q.push(i);
            do
            {
                  // extraemos el nodo u de la cola Q y exploramos 
	          // todos sus nodos adyacentes
                  u     = Q.front();
   	          Q.pop();
		  particle[u].Idgrupo= ngrupos;
		  busv(u,r0,&listvec);
		  // devuelve la lista de vecinos no visitados
                  for(j=0;j<listvec.size();j++)
	          {
	               halotmp.members.push_back(&particle[listvec[j]]);
		       particle[listvec[j]].Idgrupo    = ngrupos;
                       if(particle[listvec[j]].visitado)
			       continue;
		       else
			       particle[listvec[j]].visitado = true;
		       Q.push(listvec[j]);  //Encolar v en Q
	          }
		  listvec.clear();
            }while(!Q.empty());//agotadas todas las 
	                       //adyacencias salimos
	    if(halotmp.members.size()>=2)
	    {
		    grupo.push_back(halotmp);
	            ngrupos++;
	    }
	    halotmp.members.clear();
	}
//cout << proc << " salio iden"<<endl;
	return 0;
}

int grid(void)
{
  int i, j, k;
  int ix, iy, iz;
  float lsup;

  //printf("grid\n");
  //fflush(stdout);
  for( i = 0 ; i < nx ; i++)
    for( j = 0 ; j < np ; j++)
      for( k = 0 ; k < np ; k++)
      {
        lirst  [(i * np + j) * np + k] = -1 ;
      }

  for( i = 0 ; i < particle.size() ; i++ )  
    ll[i] = -1 ;
//  for( i = 0 ; i < particle.size() ; i++ )
//    if(&particle[i].Pos[0]==NULL)moco("no data #*$?%!!!");

//  lsup=(float)xsize - (float)overhead;
  totalsizeL=0; totalsizeR=0;
//  cout  << proc  << "   "  << facbinx  << " ||| " <<  facbinp  << " *** "  << r0  << endl;
//  printf("%10.9f\n",lsup);
  for( i = 0 ; i < particle.size() ; i++ )
  {
    ix=(int)floor((double)particle[i].Pos[0]*facbinx)  ;
    iy=(int)floor((double)particle[i].Pos[1]*facbinp)  ;
    iz=(int)floor((double)particle[i].Pos[2]*facbinp)  ;
    //ix=0;iy=0;iz=0;
    if(ix>=nx || ix < 0)
    {
	    moco("---------------------la cagaste ix");
	    cout<< proc << " " 
		<<    ix << " " 
	    << particle[i].Pos[0] << " " 
	    << facbinx << " " 
	    << facbinp << endl; 
    }
    if(iy>=np || iy < 0) moco("---------------------la cagaste iy");
    if(iz>=np || iz < 0) moco("---------------------la cagaste iz");
    lirst  [(ix * np + iy) * np + iz] = i ;
    if(fabs(xsize-particle[i].Pos[0])< 2.*overhead )  totalsizeR++;
    if(particle[i].Pos[0]            < 2.*overhead )  totalsizeL++;
  }  
 cout << proc << " proc, L "<<totalsizeL << " y R " <<  totalsizeR  << endl;
  MPI_Allreduce(&totalsizeR,&maxsizeR,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD); 
  MPI_Allreduce(&totalsizeL,&maxsizeL,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD);
  maxovh = maxsizeR > maxsizeL ? maxsizeR : maxsizeL;
//  printf("3-----\n");
//  fflush(stdout);

  for( i = 0 ; i < particle.size() ; i++ )
  {
    ix=(int)floor((double)particle[i].Pos[0]*facbinx);
    iy=(int)floor((double)particle[i].Pos[1]*facbinp);
    iz=(int)floor((double)particle[i].Pos[2]*facbinp);
    ll[lirst[(ix * np + iy) * np + iz]] = i ;
    lirst[(ix * np + iy) * np + iz] = i ;
  }  

 // printf("fin grid proc %i\n",proc);
  fflush(stdout);
  return 0;
}

int busv(int ic, float r0, vector<int> *listvec)
{
  int ixc, iyc, izc;
  int ixci, iyci, izci;
  int ixcf, iycf, izcf;
  int ix, iy, iz;
  int ixx, iyy, izz;
  int ibox;
  float xx, yy, zz, dis;
  int i;

  //Esta busv es solo no periodica con grideado en rodajas

  ixc=(int)(particle[ic].Pos[0]/xsize*nx);
  ixci=ixc-1;
  ixcf=ixc+1;
  iyc=(int)(particle[ic].Pos[1]/boxsize*np);
  iyci=iyc-1;
  iycf=iyc+1;
  izc=(int)(particle[ic].Pos[2]/boxsize*np);
  izci=izc-1;
  izcf=izc+1;

  if( ixci < 0 ) ixci = 0;
  if( iyci < 0 ) iyci = 0;
  if( izci < 0 ) izci = 0;
  if( ixcf >= nx ) ixcf = nx-1;
  if( iycf >= np ) iycf = np-1;
  if( izcf >= np ) izcf = np-1;

  for( ixx = ixci ; ixx <= ixcf ; ixx++)
  {
    ix=ixx;
    for( iyy = iyci ; iyy <= iycf ; iyy++)
    {
      iy=iyy;
      for( izz = izci ; izz <= izcf ; izz++)
      {
        iz=izz;
        ibox=(ix * np + iy) * np + iz ;
        i=lirst[ibox];
        if(i==-1)continue;
        do
        {
          i=ll[i];
	  if(particle[i].visitado && i != lirst[ibox] )continue;
	  if(particle[i].visitado && i == lirst[ibox] )break;
          xx=particle[i].Pos[0]-particle[ic].Pos[0];
          yy=particle[i].Pos[1]-particle[ic].Pos[1];
          zz=particle[i].Pos[2]-particle[ic].Pos[2];
          dis=sqrt(xx*xx+yy*yy+zz*zz);
          if( dis < r0 && particle[i].Idgrupo == -1 && i != ic )
               (*listvec).push_back(i);

        } while( i != lirst[ibox] ); /*fin laso particulas del grid*/
      } /*fin izz*/
    } /*fin iyy*/
  } /*fin ixx*/
  return 0;
}
//////////////////////////////////////////////

int groups_namesBFS2(void)
{
/*
Recorre el grafo... y renombra universalmente en cada Grupo
en principio ya cada nodp tiene un grafo unico
solo falta hacer el universal name
*/
	int i,j,k,ktot,sendproc,h,summ;
	long int *rename, *subtot;
        int total;
	long int kk;
	struct point u,v,der,izq ; 
	vector <point>::iterator ptr ;
	cola Q;
//	int root_proc;
RED;
if (proc==0) cout << "Nro maximo de Nombre grupo: " << maxngrp*numprocs << endl;
DEFA;
//	rename = new int [maxngrp*numprocs];
	rename = new long int [maxngrp];
	subtot = new long int [numprocs];
	//for(i=0;i<maxngrp*numprocs;i++)
	for(i=0;i<maxngrp;i++)
		rename[i] = -1; 

	  /*       cout << " <-proc ; conectando grupos: "<< grafo_vertices.size() << endl;
	         for(i=0;i<grafo_vertices.size();i++)
	         {   
//	             cout << " G-Vertice "<< i <<endl; fflush(stdout);

                     if(grafo_vertices[i].visitado) continue ;
                     grafo_vertices[i].visitado  = true ;
                     grafo_vertices[i].distancia = 0    ;
                     //Encolar(Q, s);
	             Q.push(grafo_vertices[i]);
		
                     do
                     {
                        // extraemos el nodo u de la cola Q y exploramos 
	                // todos sus nodos adyacentes
                        u     = Q.front();
   	                Q.pop();
///	                 cout << "@ "<< Q.size() <<endl; fflush(stdout);
	       
                        for(j=0;j<grafo_arista.size();j++)
	                {
		             if( u.name == (*(grafo_arista[j].r)).name)
		             {
	               cout << "U "<< u.name <<endl; fflush(stdout);
			           if(!(*(grafo_arista[j].l)).visitado)
			           {
                                        (*(grafo_arista[j].l)).visitado    = true            ;
                                        (*(grafo_arista[j].l)).distancia   = u.distancia + 1 ;
		                        (*(grafo_arista[j].l)).padre = grafo_vertices.begin()+(*(grafo_arista[j].r)).name;
		                        //(*(grafo_arista[j].l)).padre = 
					//	find_if( grafo_vertices.begin(), grafo_vertices.end(), 
					//			look_vertice_name(*(grafo_arista[j].r)) );
	                                Q.push(*(grafo_arista[j].l))     ;  //Encolar v en Q
			           }
		             }
		             if( u.name==(*(grafo_arista[j].l)).name)
		             {
			           if(!(*(grafo_arista[j].r)).visitado)
			           {
                                        (*(grafo_arista[j].r)).visitado    = true            ;
                                        (*(grafo_arista[j].r)).distancia   = u.distancia + 1 ;
		                        (*(grafo_arista[j].r)).padre       = grafo_vertices.begin()+(*(grafo_arista[j].l)).name;
		                        //(*(grafo_arista[j].r)).padre = 
				        //	find_if( grafo_vertices.begin(), grafo_vertices.end(), 
				        //			look_vertice_name(*(grafo_arista[j].l)) );
	                                Q.push(*(grafo_arista[j].r));//Encolar(Q, v);
			           }
		             }
	                }
                     }while(!Q.empty());
	             //agotadas todas las adyacencias salimos
	         }

	*/	
		 //renombrando padres 
		// en este caso univeralname es solo el contador de padres
	         universalname=0;
	         for(i=0;i<grafo_vertices.size();i++)
	         {
		      u=grafo_vertices[i];
	              ptr=u.padre;
	              // es padre ?
		      if( ptr ==(vector <point>::iterator )NULL)
			      rename[grafo_vertices[i].name]=universalname++; 
	         }
		 
		 for(i=0;i<numprocs;i++)
			 subtot[i]=0;
		 subtot[proc] = universalname;
		cout <<" Subtotal "<< subtot[proc] << endl << flush;
		 MPI_Allreduce(&subtot[proc],&total,numprocs,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
	if(proc==0)	cout << "TOTAL " << total << endl; 

/*		 summ=0;
		 for(i=0;i<=proc;i++)
		 {
			 subtot[i]=subtot[i]+summ;
			 summ = summ+ subtot[i];
		 }*/
		 
//	         universalname=subtot[proc];
// aqui ya se usa universalname como nombre universal
	         universalname=maxngrp*proc;
	         for(i=0;i<grafo_vertices.size();i++)
	         {
		      u=grafo_vertices[i];
	              ptr=u.padre;
	
	              // es padre ?
		      if( ptr ==(vector <point>::iterator )NULL)
		      {
		//	      grafo_vertices[i].name =universalname; 
			      rename[grafo_vertices[i].name]=universalname; 
				universalname++;
		      }
	         }
		 
	         for(i=0;i<grafo_vertices.size();i++)
   	         {
	      	      u=grafo_vertices[i];
	              ptr=u.padre;

		      // es hijo de
		      if( ptr !=(vector <point>::iterator )NULL)
	      	      {
		      	      do
		 	      {
			           v=*ptr; ptr=v.padre;
                                   if(ptr==(vector <point>::iterator)NULL)
				           break;
  		              }while(1);
	   	              if(grafo_vertices[i].name<maxngrp*numprocs)
			      {
				      grafo_vertices[i].name = v.name ;
				      rename[grafo_vertices[i].name] = v.name ;
			      }
			      else
			      {
				      LGREEN;
				      cout<< "la cagaste aca  " << proc << " " <<grafo_vertices[i].name <<endl;
				      DEFA;
			      }
	   	      }
 	         }
		 
/*	for(i=0;i<maxngrp*numprocs;i++)
	{
	if(proc==0)cout << setw(40) << "\r Porcentaje rename " << 100.0*i/(maxngrp*numprocs) ;
            k = rename[i]>-1 ? 1 : 0; ktot=0;
            MPI_Allreduce(&k,&ktot,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
	    if(ktot>1)
	    {
		    cout << rename[i] << " | " << proc << " -- " << ktot << endl;
		    moco("mas de uno en rename\n");FIN;
	    }
	    if(ktot==0)
	    {
		    //el grupo no existe pero eso esta permitido
		    if(i==maxngrp*numprocs-1)break;
		    continue;
	    }
	    k = k==1 ? proc : -1;
	    MPI_Allreduce(&k,&ktot,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD);
	    MPI_Barrier(MPI_COMM_WORLD);
            MPI_Bcast(&rename[i],1,MPI_INT,ktot,MPI_COMM_WORLD);
	    MPI_Barrier(MPI_COMM_WORLD);
	}*/

cout << "test 2"	<< endl << flush;

	ofstream Salida ;
      	char fileout[100];
      	sprintf(fileout,"Nombres.%d.dat",proc);

      	Salida.open(fileout);
	//for(i=maxngrp*proc;i<maxngrp*(proc+1);i++)
	for(i=0;i<maxngrp*numprocs;i++)

	{
//		if(rename[i]>-1)
//	if(i==maxngrp*proc) cout << "entre salida" << endl << flush ;
	if(i==0) cout << "entre salida" << endl << flush ;
			Salida << i << " renombrado a: " << rename[i] << endl;
//	if(i==maxngrp*(proc+1)) cout << "sali salida" << endl << flush ;
	if(i==maxngrp*numprocs-1) cout << "sali salida" << endl << flush ;
	}
//	Salida << "hola!!!!" << endl;	
      	Salida.close();

cout << "sip sip sip"<< endl;
FIN;

	for(i=0;i<particle.size();i++)
	{
		particle[i].Idgrupo=rename[particle[i].Idgrupo];
//                if(particle[i].Idgrupo>=0)numero[particle[i].Idgrupo]++;
	}
FIN;
	return 0;
};
